package com.lframework.jh.push.api.listeners;

import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.Method;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.lframework.jh.push.core.components.mq.MqProducer;
import com.lframework.jh.push.core.components.sign.CheckSignFactory;
import com.lframework.jh.push.core.constants.MqConstants;
import com.lframework.jh.push.core.utils.DateUtil;
import com.lframework.jh.push.core.utils.IdUtil;
import com.lframework.jh.push.core.utils.JsonUtil;
import com.lframework.jh.push.core.utils.StringUtil;
import com.lframework.jh.push.plugin.core.dto.NotifySmsBatchDto;
import com.lframework.jh.push.service.entity.NotifyData;
import com.lframework.jh.push.service.entity.PushOrder;
import com.lframework.jh.push.service.entity.SmsBatchDetail;
import com.lframework.jh.push.service.service.NotifyDataService;
import com.lframework.jh.push.service.service.PushOrderService;
import com.lframework.jh.push.service.service.SmsBatchDetailService;
import java.util.HashMap;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class NotifySmsBatchListener {

    @Autowired
    private SmsBatchDetailService smsBatchDetailService;

    @Autowired
    private NotifyDataService notifyDataService;

    @Autowired
    private PushOrderService pushOrderService;

    @Autowired
    private MqProducer mqProducer;

    @Autowired
    private CheckSignFactory checkSignFactory;

    @JmsListener(destination = MqConstants.QUEUE_NOTIFY_SMS_BATCH)
    public void execute(NotifySmsBatchDto dto) {
        log.info("【第三步】接收到通知第三方短信批次请求 dto {}", dto);
        if (StringUtil.isNotBlank(dto.getNotifyId())) {
            log.info("【第三步】dto中存在notifyId，直接使用");
            NotifyData notifyData = notifyDataService.getById(dto.getNotifyId());
            this.doNotify(notifyData.getNotifyUrl(), notifyData.getContent(), dto);
            return;
        }
        PushOrder pushOrder = pushOrderService.getById(dto.getOrderId());
        if (pushOrder == null) {
            log.warn("推送单 {} 不存在，不发起通知", dto.getOrderId());
            return;
        }

        Map<String, String> notifyContent = this.buildNotifyContent(pushOrder, dto);
        if (notifyContent == null) {
            return;
        }

        NotifyData notifyData = new NotifyData();
        notifyData.setMchId(pushOrder.getMchId());
        notifyData.setId(IdUtil.getId());
        notifyData.setNotifyUrl(pushOrder.getNotifyUrl());
        notifyData.setBatchNo(dto.getBatchNo());
        notifyData.setContent(JsonUtil.toJsonString(notifyContent));
        notifyDataService.save(notifyData);

        dto.setNotifyId(notifyData.getId());

        this.doNotify(pushOrder.getNotifyUrl(), notifyData.getContent(), dto);
    }

    private Map<String, String> buildNotifyContent(PushOrder pushOrder, NotifySmsBatchDto dto) {

        Map<String, Object> content = new HashMap<>();
        content.put("id", pushOrder.getId());
        content.put("mchId", pushOrder.getMchId());
        content.put("appId", pushOrder.getAppId());
        content.put("channel", pushOrder.getChannel());
        content.put("outerNo", pushOrder.getOuterNo());
        content.put("bizId", pushOrder.getBizId());
        content.put("status", pushOrder.getStatus().getCode());
        content.put("createTime", DateUtil.formatDateTime(pushOrder.getCreateTime()));
        content.put("channelResp", JsonUtil.parseObj(pushOrder.getChannelResp()));
        content.put("successTime", pushOrder.getSuccessTime() == null ? null
            : DateUtil.formatDateTime(pushOrder.getSuccessTime()));
        content.put("failureTime", pushOrder.getFailureTime() == null ? null
            : DateUtil.formatDateTime(pushOrder.getFailureTime()));
        content.put("errorMsg",
            StringUtil.isNotBlank(pushOrder.getErrorMsg()) ? pushOrder.getErrorMsg() : null);
        content.put("batchNo", pushOrder.getBatchNo());
        content.put("param1", pushOrder.getParam1());
        content.put("param2", pushOrder.getParam2());

        Wrapper<SmsBatchDetail> queryWrapper = Wrappers.lambdaQuery(SmsBatchDetail.class)
            .eq(SmsBatchDetail::getBatchNo, pushOrder.getBatchNo())
            .eq(SmsBatchDetail::getPhoneNumber, dto.getPhoneNumber());
        SmsBatchDetail smsBatchDetail = smsBatchDetailService.getOne(queryWrapper);
        if (smsBatchDetail == null) {
            log.warn("batchNo {} phoneNumber {} 批次明细不存在", pushOrder.getBatchNo(),
                dto.getPhoneNumber());
            return null;
        }
        Map<String, Object> batch = new HashMap<>();
        batch.put("batchNo", pushOrder.getBatchNo());
        batch.put("phoneNumber", dto.getPhoneNumber());
        batch.put("status", smsBatchDetail.getStatus().getCode());
        batch.put("createTime", DateUtil.formatDateTime(smsBatchDetail.getCreateTime()));
        batch.put("successTime", smsBatchDetail.getSuccessTime() == null ? null
            : DateUtil.formatDateTime(smsBatchDetail.getSuccessTime()));
        batch.put("smsContent", smsBatchDetail.getSmsContent());
        batch.put("errorMsg", smsBatchDetail.getErrorMsg());
        batch.put("bizId", smsBatchDetail.getBizId());

        content.put("batchDetail", batch);

        String params = JsonUtil.toJsonString(content);
        Map<String, String> result = checkSignFactory.getInstance()
            .wrap(pushOrder.getMchId(), params);
        String mchId = result.get("mchId");
        String timestamp = result.get("timestamp");
        String nonceStr = result.get("nonceStr");
        result.put("sign", checkSignFactory.getInstance()
            .sign(Integer.valueOf(mchId), timestamp, nonceStr, params));

        return result;
    }

    private void doNotify(String notifyUrl, String notifyContent, NotifySmsBatchDto dto) {

        log.info("【第三步】开始通知第三方, notifyUrl {}, notifyContent {} dto {}", notifyUrl,
            notifyContent, dto);

        String resp = null;
        try {
            HttpResponse response = HttpUtil.createRequest(Method.POST, notifyUrl)
                .body(notifyContent).setConnectionTimeout(1000).setReadTimeout(5000).execute();
            resp = response.body();
            if (!"success".equalsIgnoreCase(resp)) {
                throw new RuntimeException("第三方返回结果 " + resp + " 不是success");
            }
        } catch (Exception e) {
            log.warn(e.getMessage(), e);
            int index = dto.getCurrentIndex();
            if (index >= MqConstants.NOTIFY_RETRY_SECONDS.length) {
                log.info("【第三步】{} 重试次数过多，停止通知", notifyUrl);
                return;
            }
            dto.setCurrentIndex(dto.getCurrentIndex() + 1);
            mqProducer.sendDelayMessage(MqConstants.QUEUE_NOTIFY_SMS_BATCH, dto,
                MqConstants.NOTIFY_RETRY_SECONDS[index] * 1000L);
        } finally {
            notifyDataService.addNotifyCount(dto.getNotifyId(), resp);
        }

    }
}
